/*
	项目开始日期2021.12.11
	适用于高精度科学快速计算的Floating类开发者LiYinan(2005)@MacroModel
	版本：2021b1

	Copyright (c) (2021) Yinan,L. All rights reserved.
	mmNumCore2021 is authored by (2021)  Yinan,L.(2005) and supported by MacroModel Simulation Team.
*/

#include "highnum.h"
#include <omp.h>

inline highNum::highNum()
{
	type.setTypeId(TYPE_FLOATING);
	indexPart = 0;
	isPositive = true;
}

inline highNum::highNum(oldHighNum& integer)
{
	type.setTypeId(TYPE_FLOATING);
	integer.check();
	indexPart = 0;
	integer.check();
	isPositive = integer.positive();
	if (integer.int_part().size() == 1 && integer.int_part()[0] == 0 && integer.dec_part().size())//纯小数且不为0
		for (size_t i = 0; i < integer.dec_part().size(); i++)
			decPart.push_back(integer.dec_part()[i]);//等着后面check检查
	else
	{
		indexPart = integer.int_part().size();
		for (size_t i = 0; i < integer.size(); i++)
			decPart.push_back(integer[i]);
	}
	check();
}

inline highNum::highNum(rsp::_Num Integer) 
{
	type.setTypeId(TYPE_FLOATING);
	isPositive = (Integer >= 0);
	indexPart = 2;
	Integer = (Integer >= 0 ? Integer : -Integer);
	decPart.push_back(Integer / UPPER_LIMIT);
	decPart.push_back(Integer % UPPER_LIMIT);
	carry();
}

inline highNum::highNum(string& arg)
{
	type.setTypeId(TYPE_FLOATING);
	try
	{
		setVal(arg);
	}
	catch (const std::exception&)
	{
		cerr << "Incorrect input" << endl;
		decPart.clear();//剩下的交给check
	} 
	carry();
}

inline Object* highNum::copy()
{
	Object* res = new highNum;
	*(highNum*)res = *this;
	res->initReference();
	return res;
}

inline string highNum::toString()
{
	check();
	string temp;
	if (!isPositive)//正负号
		temp += '-';
	if (decPart.size() == 0)
		temp = "0";
	else if (indexPart <= 0)
	{
		temp += "0.";
		for (size_t i = 0; i < -indexPart; i++)
			temp += "000000000";
		for (size_t i = 0; i < decPart.size(); i++)
		{
			if (i != (decPart.size() - 1))
				temp += numToStr(decPart[i]);
			else//最后一项
			{
				string c = numToStr(decPart[i]);
				while (c.back() == '0')//删除末尾为0
					c.pop_back();
				temp += c;
			}
		}
	}
	else
	{
		temp += eleToStr(decPart[0]);
		rsp::_Num i;
		for (i = 1; i < indexPart; i++)
			temp += (i < decPart.size() ? numToStr(decPart[i]) : "000000000");
		if (i < decPart.size())
		{
			temp += ".";
			while (i < decPart.size())
			{
				if (i != (decPart.size() - 1))
					temp += numToStr(decPart[i]);
				else//最后一项
				{
					string c = numToStr(decPart[i]);
					while (c.back() == '0')//删除末尾为0
						c.pop_back();
					temp += c;
				}
				i++;
			}
		}
	}
	return temp;
}


inline void highNum::check()//处理无效精度位
{
	if (decPart.size())// !=0
	{
		while (decPart.size() && decPart.back() == 0)
			decPart.pop_back();
		size_t sizeTemp = 0;
		while (decPart.size() && decPart[sizeTemp] == 0)
			sizeTemp++;
		if (sizeTemp > 0)
		{
			decPart.erase(decPart.begin(), decPart.begin() + sizeTemp);
			indexPart -= sizeTemp;
		}
	}
	if (!decPart.size())// ==0
	{
		indexPart = 0;
		isPositive = true;
	}
}

inline void highNum::carry(bool alwaysCheck, size_t end, size_t maxbit, bool checked)//严格依赖串行，多线程算法可能会提高时间复杂度
{
	for (rsp::_Num i = (decPart.size() - 1 - end > 0 ? decPart.size() - 1 - end : 0); i >= 0 && maxbit > 0; i--)
	{
		if (decPart[i] >= UPPER_LIMIT)
		{
			if (i != 0)
			{
				decPart[i - 1] += decPart[i] / UPPER_LIMIT;
				decPart[i] %= UPPER_LIMIT;
			}
			else
			{
				while (decPart[0] >= UPPER_LIMIT)
				{
					decPart.insert(decPart.begin(), decPart[0] / UPPER_LIMIT);
					decPart[1] %= UPPER_LIMIT;
					indexPart++;
				}
			}
		}
		else if (!alwaysCheck)
			return;
		maxbit--;
	}
	if (checked)
		check();
}

inline void highNum::borrow()//注意，只处理非0！
{
	for (rsp::_Num i = decPart.size() - 1; i > 0; i--)
		if (decPart[i] < 0)
		{
			decPart[i - 1] -= 1;
			decPart[i] += UPPER_LIMIT;
		}
	check();
}

inline void highNum::retentionAccuracy(size_t length, bool isDecPart)
{
	check();
	if (!decPart.size())
		return;
	if (isDecPart)//目前只有decPart才有进位处理
	{
		if (length / 9 + indexPart + 1 <= decPart.size())
		{
			decPart.erase(decPart.begin() + (length / 9 + indexPart + 1 > 0 ? length / 9 + indexPart + 1 : 0), decPart.end());
			if (decPart.size() - (indexPart > 0 ? indexPart : 0) > 0 && indexPart < decPart.size())
			{
				rsp::_Num carryTemp = decPart.back() / rsp::_Num(pow(10, 8 - length % 9)) % 10;
				carryTemp = (carryTemp > 4 ? rsp::_Num(pow(10, 9 - length % 9)) : 0);
				decPart.back() -= decPart.back() % rsp::_Num(pow(10, 9 - length % 9));
				decPart.back() += carryTemp;
				carry(false);
			}
		}
	}
	else //float没有进位处理
	{
		if (divideCeil(length, 9) <= decPart.size())
		{
			rsp::_Num temp = 0, i = decPart[0];
			while (i / 100000000 == 0)
			{
				temp++;
				i *= 10;
			}
			decPart.erase(decPart.begin() + divideCeil(length, 9), decPart.end());
			if (decPart.size())//  !=0
			{
				if (decPart.size() == 1)
					decPart[0] = decPart[0] / rsp::_Num(pow(10, (9 - temp - length > 0 ? 9 - temp - length : 0))) * rsp::_Num(pow(10, (9 - temp - length > 0 ? 9 - temp - length : 0)));
				else //if (decPart.size() > 1)
					decPart.back() = decPart.back() / rsp::_Num(pow(10, 9 - (temp + length) % 9)) * rsp::_Num(pow(10, 9 - (temp + length) % 9));
			}
			carry(false);
		}
	}
	check();
}

inline rsp::_Num highNum::getEffectiveDigitalAccuracy()
{
	check();
	if (!decPart.size())
		return 0;
	rsp::_Num length = 9 * decPart.size(), i;
	i = decPart[0];
	while (i / 100000000 == 0)
	{
		length--;
		i *= 10;
	}
	i = 10;
	while (decPart.back() % i == 0)
	{
		length--;
		i *= 10;
	}
	return length;
}

long double highNum::toFloat()
{
	check();
	if (indexPart > 4096)
		throw("highNum::toFloat(), The maximum limit for conversion has been exceeded!");
	long double temp = 0;
	for (size_t i = 0; i < (decPart.size() < 30 ? decPart.size() : 30); i++)
		temp = temp * UPPER_LIMIT + decPart[i];
	temp /= pow(UPPER_LIMIT, (decPart.size() < 30 ? decPart.size() : 30) - indexPart);
	return temp;
}

inline void highNum::setVal(string arg)//对特殊符号的处理未做
{
	isPositive = (arg[0] != '-');
	if (arg.find('-', 1) != string::npos || arg.find('+', 1) != string::npos)
	{
		cerr << "Incorrect input" << endl;
		decPart.clear();
		check();
		return;
	}
	decPart.clear();
	size_t start = 0, end = arg.size() - 1;
	arg += '.';
	size_t point = arg.find('.');
	arg.pop_back();
	if (!isPositive || arg[0] == '+')
		start = 1;//有效数字计算位数
	if (point < start)
		point = start + 1;
	while (arg[start] == 0)
		start++;
	indexPart = divideCeil(point - start, 9);
	decPart.push_back(stoll(arg.substr(start, ((point - start) % 9 ? (point - start) % 9 : 9))));
	start += ((point - start) % 9 ? (point - start) % 9 : 9);
	while (start < point)
	{
		decPart.push_back(stoll(arg.substr(start, 9)));
		start += 9;
	}
	if (start >= point)//小数
	{
		start = point + 1;
		arg += "000000000";
		while (start <= end)
		{
			decPart.push_back(stoll(arg.substr(start, 9)));
			start += 9;
		}
	}
	check();
}

inline void highNum::set_zero()
{ 
	isPositive = true; 
	decPart.clear(); 
	indexPart = 0; 
}

inline void highNum::set_float(long double f)
{
	set_zero();

	if (f == 0)
	{
		indexPart = 0;
		return;
	}
	isPositive = (f >= 0);
	f = (f >= 0 ? f : -f);
	int index = log10(f);
	f /= pow(10, ++index);//0.?????*10^index
	if (index % 9 == 0)
		indexPart = index / 9;
	else if (index % 9 > 0)
	{
		indexPart = static_cast<rsp::_Num>(index / 9) + 1;//上取整
		f /= pow(10, 9 * indexPart - index);
	}
	else //if (index % 9 < 0)
	{
		indexPart = index / 9;
		f *= pow(10, index % 9);
	}
	if (indexPart < -100000000)
	{
		decPart.clear();
		indexPart = 0;
		clog << "warning: Infinitesimal, rounded to 0" << endl;
		return;
	}
	for (short i = 0; i < 15; i++)
	{
		f *= 1000000000;
		decPart.push_back(rsp::_Num(f));
		f -= rsp::_Num(f);
	}
	check();
}
//func

inline int compare(highNum& arg1, highNum& arg2, bool gnoreSymbol)//1代表大于,0代表等于,-1代表小于
{
	arg1.check();
	arg2.check();
	if ((arg1.positive() != arg2.positive()) && !gnoreSymbol)
		return (arg1.positive() ? 1 : -1);
	else
	{
		if (arg1.index_part() > arg2.index_part())
			return 1;
		else if (arg1.index_part() < arg2.index_part())
			return -1;
		else
		{
			for (size_t i = 0; i < (arg1.dec_part().size() < arg2.dec_part().size() ? arg1.dec_part().size() : arg2.dec_part().size()); i++)
				if (arg1.dec_part()[i] > arg2.dec_part()[i])
					return 1;
				else if (arg1.dec_part()[i] < arg2.dec_part()[i])
					return -1;	
			if (arg1.dec_part().size() == arg2.dec_part().size())//比较完后都相等？
				return 0;
			else
				return (arg1.dec_part().size() > arg2.dec_part().size() ? 1 : -1);
		}
	}
}

inline highNum adder(highNum& arg1, highNum& arg2, bool isMinus)
{
	highNum temp1;
	bool oneortwo;//f=1,t=2
	if ((arg1.positive() != arg2.positive()) ^ isMinus)//-
	{
		if (compare(arg1, arg2, true) != -1)//arg1>=arg2
		{
			temp1 = arg1;
			oneortwo = true;
		}
		else//arg<arg2
		{
			temp1 = arg2;
			oneortwo = false;
		}
		if (temp1.index_part() - (oneortwo ? arg2 : arg1).index_part() + (oneortwo ? arg2 : arg1).dec_part().size() > temp1.dec_part().size())
			temp1.dec_part().resize(temp1.index_part() - (oneortwo ? arg2 : arg1).index_part() + (oneortwo ? arg2 : arg1).dec_part().size(), 0);
		for (size_t i = temp1.index_part() - (oneortwo ? arg2 : arg1).index_part(), t = 0; t < (oneortwo ? arg2 : arg1).dec_part().size(); i++, t++)
				temp1.dec_part()[i] -= (oneortwo ? arg2 : arg1).dec_part()[t];
		temp1.borrow();
	}
	else//+
	{
		if (compare(arg1, arg2, true) != -1)//arg1>=arg2
		{
			temp1 = arg1;
			oneortwo = true;
		}
		else//arg<arg2
		{
			temp1 = arg2;
			oneortwo = false;
		}
		if (temp1.index_part() - (oneortwo ? arg2 : arg1).index_part() + (oneortwo ? arg2 : arg1).dec_part().size() > temp1.dec_part().size())
			temp1.dec_part().resize(temp1.index_part() - (oneortwo ? arg2 : arg1).index_part() + (oneortwo ? arg2 : arg1).dec_part().size(), 0);
		for (size_t i = temp1.index_part() - (oneortwo ? arg2 : arg1).index_part(), t = 0; t < (oneortwo ? arg2 : arg1).dec_part().size(); i++, t++)
				temp1.dec_part()[i] += (oneortwo ? arg2 : arg1).dec_part()[t];
		temp1.carry();
	}
	temp1.check();
	return temp1;
}

inline vector<double> hnTodouble9(highNum& hn)
{
	vector<double> temp;
	hn.check();
	temp.reserve(9 * hn.dec_part().size());
	for (rsp::_Num i = hn.dec_part().size() - 1; i >= 0; i--)
	{
		temp.push_back(hn.dec_part()[i] % 10);
		temp.push_back(hn.dec_part()[i] % 100 / 10);
		temp.push_back(hn.dec_part()[i] % 1000 / 100);
		temp.push_back(hn.dec_part()[i] % 10000 / 1000);
		temp.push_back(hn.dec_part()[i] % 100000 / 10000);
		temp.push_back(hn.dec_part()[i] % 1000000 / 100000);
		temp.push_back(hn.dec_part()[i] % 10000000 / 1000000);
		temp.push_back(hn.dec_part()[i] % 100000000 / 10000000);
		temp.push_back(hn.dec_part()[i] / 100000000);
	}
	return temp;
}

inline void hnSwap(double& x, double& y)//inline warning?
{
	double t = x;
	x = y;
	y = t;
}

inline rsp::_Num hnRev(rsp::_Num x, rsp::_Num len)//inline warning?
{
	rsp::_Num ans = 0, i;
	for (i = 0; i < len; i++) 
	{
		ans <<= 1;
		ans |= (x & 1);
		x >>= 1;
	}
	return ans;
}

inline void hnFFT(vector<double>& reA, vector<double>& inA, bool flag)
{
	const double hnpi = 3.14159265358979323846;
	rsp::_Num s, i;
	const rsp::_Num n = reA.size();
	const rsp::_Num lgn = log(n) / log(2);
	#pragma omp simd
	for (i = 0; i < n; i++)
	{
		rsp::_Num j = hnRev(i, lgn);
		if (j > i)
		{
			hnSwap(reA[i], reA[j]);
			hnSwap(inA[i], inA[j]);
		}
	}
	for (s = 1; s <= lgn; s++) 
	{
		rsp::_Num m = (1ll << s);
		double reWm = cos(2 * hnpi / m), inWm = sin(2 * hnpi / m);
		if (flag)
			inWm = -inWm;
		for (rsp::_Num k = 0; k < n; k += m)
		{
			double reW = 1.0, inW = 0.0;
			for (rsp::_Num j = 0; j < m / 2; j++)
			{
				rsp::_Num tag = k + j + m / 2;
				double reT = reW * reA[tag] - inW * inA[tag];
				double inT = reW * inA[tag] + inW * reA[tag];
				double reU = reA[k + j], inU = inA[k + j];
				reA[k + j] = reU + reT;
				inA[k + j] = inU + inT;
				reA[tag] = reU - reT;
				inA[tag] = inU - inT;
				double rew_t = reW * reWm - inW * inWm;
				double inw_t = reW * inWm + inW * reWm;
				reW = rew_t;
				inW = inw_t;
			}
		}
	}
	if (flag)
	{
		#pragma omp simd
		for (i = 0; i < n; i++)
		{
			reA[i] /= n;
			inA[i] /= n;
		}
	}
}

inline highNum multiply(highNum& arg1, highNum& arg2, bool useFFT)
{
	highNum temp;
	arg1.check();
	arg2.check();
	if (arg1.dec_part().size() == 0 || arg2.dec_part().size() == 0)
		return 0;
	else if (arg1 == 1)
		return arg2;
	else if (arg1 == -1)
	{
		temp = arg2;
		temp.positive() = !arg2.positive();
		return temp;
	}
	else if (arg2 == 1)
		return arg1;
	else if (arg2 == -1)
	{
		temp = arg1;
		temp.positive() = !arg1.positive();
		return temp;
	}
	temp.positive() = (arg1.positive() == arg2.positive());
	if (useFFT)
	{
		const size_t lengthlog = pow(2, size_t(log2(9 * (arg1.dec_part().size() > arg2.dec_part().size() ? arg1.dec_part().size() : arg2.dec_part().size())) + 2));
		vector<double> arg1_r = hnTodouble9(arg1), arg1_i, arg2_r = hnTodouble9(arg2), arg2_i;
		arg1_r.resize(lengthlog, 0);
		arg1_i.resize(lengthlog, 0);
		arg2_r.resize(lengthlog, 0);
		arg2_i.resize(lengthlog, 0);
		hnFFT(arg1_r, arg1_i, false);
		hnFFT(arg2_r, arg2_i, false);
		#pragma omp simd
		for (size_t i = 0; i < lengthlog; i++)
		{
			double rec = arg1_r[i] * arg2_r[i] - arg1_i[i] * arg2_i[i];
			double inc = arg1_r[i] * arg2_i[i] + arg1_i[i] * arg2_r[i];
			arg1_r[i] = rec; arg1_i[i] = inc;
		}
		hnFFT(arg1_r, arg1_i, true);
		temp.dec_part().resize(lengthlog / 9 + 1, 0);
		const size_t arg1_r_size = arg1_r.size();
		size_t t = 0, r = 0;
		#pragma omp simd
		for (rsp::_Num i = lengthlog / 9; i >= 0; i--)
		{
			temp.dec_part()[i] += (t < arg1_r_size ? rsp::_Num(arg1_r[t] + 0.5) % UPPER_LIMIT : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 1 ? rsp::_Num(arg1_r[t + 1] + 0.5) % UPPER_LIMIT * 10 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 2 ? rsp::_Num(arg1_r[t + 2] + 0.5) % UPPER_LIMIT * 100 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 3 ? rsp::_Num(arg1_r[t + 3] + 0.5) % UPPER_LIMIT * 1000 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 4 ? rsp::_Num(arg1_r[t + 4] + 0.5) % UPPER_LIMIT * 10000 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 5 ? rsp::_Num(arg1_r[t + 5] + 0.5) % UPPER_LIMIT * 100000 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 6 ? rsp::_Num(arg1_r[t + 6] + 0.5) % UPPER_LIMIT * 1000000 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 7 ? rsp::_Num(arg1_r[t + 7] + 0.5) % UPPER_LIMIT * 10000000 : 0);
			temp.dec_part()[i] += (t < arg1_r_size - 8 ? rsp::_Num(arg1_r[t + 8] + 0.5) % UPPER_LIMIT * 100000000 : 0);
			t += 9;
		}
		temp.carry(true, 0, LLONG_MAX, false);
		while (temp.dec_part()[r] == 0)
			r++;
		temp.dec_part().erase(temp.dec_part().begin(), temp.dec_part().begin() + r);
		temp.index_part() = temp.dec_part().size() - (arg1.dec_part().size() - arg1.index_part() > 0 ? arg1.dec_part().size() - arg1.index_part() : 0) - (arg2.dec_part().size() - arg2.index_part() > 0 ? arg2.dec_part().size() - arg2.index_part() : 0);
		temp.carry();
	}
	else
	{
		temp.index_part() = arg1.index_part() + arg2.index_part();
		temp.dec_part().assign(arg1.dec_part().size() + arg2.dec_part().size(), 0);
		rsp::_Num checktTemp = 0;
		for (rsp::_Num i = arg1.dec_part().size() - 1; i >= 0; i--)
		{
			#pragma omp simd
			for (rsp::_Num j = arg2.dec_part().size() - 1; j >= 0; j--)
				temp.dec_part()[i + j + 1] += arg1.dec_part()[i] * arg2.dec_part()[j];
			temp.carry(true, checktTemp++, arg2.dec_part().size(), false);
		}
		temp.check();
	}
	return temp;
}

inline highNum divide(highNum& arg1, highNum& arg2, size_t length)
{
	highNum temp;
	arg1.check();
	arg2.check();
	bool positiveres = (arg1.positive() == arg2.positive());
	if (arg2.dec_part().size() == 0)
		throw("Divisor cannot be zero!");
	else if (arg1.dec_part().size() == 0)
		return 0;
	else if (arg2 == 1)
		return arg1;
	else if (arg2 == -1)
	{
		temp = arg1;
		temp.positive() = !arg1.positive();
		return temp;
	}
	else if (arg2.dec_part().size() == 1)
	{
		temp = arg1;
		rsp::_Num rectemp = 0, argf = arg2.dec_part().back();
		for (rsp::_Num i = 0; i < arg1.index_part() + length + 1; i++)
		{
			if (i >= arg1.dec_part().size())
				temp.dec_part().push_back(0);
			temp.dec_part()[i] += rectemp * UPPER_LIMIT;
			rectemp = temp.dec_part()[i] % argf;
			temp.dec_part()[i] /= argf;
		}
	}
	else if (arg1.dec_part() == arg2.dec_part())
	{
		temp.dec_part().push_back(1);
		temp.index_part() = arg1.index_part() - arg2.index_part() + 1;
	}
	else
	{
		temp.index_part() = 1 - arg2.index_part();
		temp.dec_part().push_back(UPPER_LIMIT / ((arg2.dec_part()[0] + 1) == 1 ? 2 : (arg2.dec_part()[0] + 1)));
		highNum tempold = 0;
		while (tempold != temp)
		{
			tempold = temp;
			temp  *= (arg2.index_part() ? (2 - temp * arg2) : (2 + temp * arg2));
			temp.retentionAccuracy(length + 27 + 9 * arg1.index_part());
		}//方便优化
		if (arg1 != 1)
			temp *= arg1;
	}
	temp.positive() = positiveres;
	temp.retentionAccuracy(length);
	temp.check();
	return temp;
}

inline highNum mod(highNum& arg1, highNum& arg2, size_t length)
{
	highNum temp;
	temp = divide(arg1, arg2, length);
	temp = arg1 - (temp * arg2);
	return temp;
}

//highNum pow(highNum& arg1, highNum& arg2, size_t length)//this!!!!!!!!!!!!!!!!!!!!!!!!!!
//{
//	arg1.check();
//	arg2.check();
//	highNum temp;
//	if (arg2.index_part() > 1 || arg1.index_part() * 9 * arg2.dec_part()[0] > INT_MAX)//超过限制
//		throw("pow: The result is too large!");
//	else if (arg1 == 1)//1^n
//		return 1;
//	else if (arg1 == -1)//-1^n
//	{
//		highNum two = 2;
//		if (mod(arg2, two, (arg2.dec_part().size() - arg2.index_part() > 0 ? arg2.dec_part().size() - arg2.index_part() : 0)) == 0)
//		{
//
//		}
//		else
//			throw("Maths Error: meaningless");
//	}
//	else if (arg1 == 0)//0^n ,except 0^0
//	{
//		if (arg2 == 0)
//			throw ("Maths Error: 0^0 isn't allowed!");
//		else
//			return 0;
//	}
//	else if (arg2 == 1)//n^1
//	{
//		temp = arg1;
//		temp.retentionAccuracy(length);
//	}
//	else if (arg2 == 0)//0^0 was thrown before!
//		return 1;
//	else if (arg2 == -1)
//	{
//
//	}
//	else
//	{
//		bool reciprocal = false;
//		if (!arg2.index_part())
//			reciprocal = true;
//
//	}
//	return temp;
//}

ostream& operator<<(ostream& os, highNum arg)
{
	os << arg.toString();
	return os;
}

istream& operator>>(istream& is, highNum &arg)
{
	string s;
	is >> s;
	try
	{
		arg.setVal(s);
	}
	catch (const std::exception&)
	{
		cerr << "Incorrect input" << endl;
		arg.dec_part().clear();
		arg.check();
	}
	return is;
}

bool operator ==(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) == 0)
		return true;
	else
		return false;
}

bool operator ==(highNum&& arg1, highNum& arg2)
{
	return arg1 == arg2;
}

bool operator ==(highNum& arg1, highNum&& arg2)
{
	return arg1 == arg2;
}

bool operator ==(highNum&& arg1, highNum&& arg2)
{
	return arg1 == arg2;
}

bool operator !=(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) != 0)
		return true;
	else
		return false;
}

bool operator !=(highNum&& arg1, highNum& arg2)
{
	return arg1 != arg2;
}

bool operator !=(highNum& arg1, highNum&& arg2)
{
	return arg1 != arg2;
}

bool operator !=(highNum&& arg1, highNum&& arg2)
{
	return arg1 != arg2;
}

bool operator >(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) == 1)
		return true;
	else
		return false;
}

bool operator >(highNum&& arg1, highNum& arg2)
{
	return arg1 > arg2;
}

bool operator >(highNum& arg1, highNum&& arg2)
{
	return arg1 > arg2;
}

bool operator >(highNum&& arg1, highNum&& arg2)
{
	return arg1 > arg2;
}

bool operator >=(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) >= 0)
		return true;
	else
		return false;
}

bool operator >=(highNum&& arg1, highNum& arg2)
{
	return arg1 >= arg2;
}

bool operator >=(highNum& arg1, highNum&& arg2)
{
	return arg1 >= arg2;
}

bool operator >=(highNum&& arg1, highNum&& arg2)
{
	return arg1 >= arg2;
}

bool operator <(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) == -1)
		return true;
	else
		return false;
}

bool operator <(highNum&& arg1, highNum& arg2)
{
	return arg1 < arg2;
}

bool operator <(highNum& arg1, highNum&& arg2)
{
	return arg1 < arg2;
}

bool operator <(highNum&& arg1, highNum&& arg2)
{
	return arg1 < arg2;
}

bool operator <=(highNum& arg1, highNum& arg2)
{
	if (compare(arg1, arg2) <=0)
		return true;
	else
		return false;
}

bool operator <=(highNum&& arg1, highNum& arg2)
{
	return arg1 <= arg2;
}

bool operator <=(highNum& arg1, highNum&& arg2)
{
	return arg1 <= arg2;
}

bool operator <=(highNum&& arg1, highNum&& arg2)
{
	return arg1 <= arg2;
}

highNum operator +(highNum& arg1, highNum& arg2) 
{
	return adder(arg1, arg2, false);
}

highNum operator +(highNum&& arg1, highNum& arg2) 
{
	return arg1 + arg2;
 }

highNum operator +(highNum& arg1, highNum&& arg2)
{
	return arg1 + arg2;
 }

highNum operator +(highNum&& arg1, highNum&& arg2)
{
	return arg1 + arg2;
 }

highNum operator +=(highNum& arg1, highNum arg2)
{
	return arg1 = arg1 + arg2;
 }

highNum operator -(highNum& arg1, highNum& arg2)
{
	return adder(arg1, arg2, true);
 }

highNum operator -(highNum&& arg1, highNum& arg2)
{
	return arg1 - arg2;
 }

highNum operator -(highNum& arg1, highNum&& arg2)
{
	return arg1 - arg2;
 }

highNum operator -(highNum&& arg1, highNum&& arg2) 
{
	return arg1 - arg2;
 }

highNum operator -=(highNum& arg1, highNum arg2)
{
	return arg1 - arg2;
 }

highNum operator *(highNum& arg1, highNum& arg2)
{
	highNum temp;
	if (arg1.dec_part().size() > 2147483648 || arg2.dec_part().size() > 2147483648)
		cerr << "multiply: too large" << endl;
	else if ((arg1.dec_part().size() < 5 || arg2.dec_part().size() < 5) || (arg1.dec_part().size() < 32 && arg2.dec_part().size() < 32))
		temp = multiply(arg1, arg2, false);
	else
		temp = multiply(arg1, arg2, true);
	return temp;
}

highNum operator *(highNum&& arg1, highNum& arg2)
{
	return arg1 * arg2;
}

highNum operator *(highNum& arg1, highNum&& arg2)
{
	return arg1 * arg2;
}

highNum operator *(highNum&& arg1, highNum&& arg2)
{
	return arg1 * arg2;
}

highNum operator *=(highNum& arg1, highNum arg2)
{
	return arg1 = arg1 * arg2;
}

highNum operator /(highNum& arg1, highNum& arg2)
{
	highNum temp;
	try
	{
		temp = divide(arg1, arg2);
	}
	catch (const char* errmsg)
	{
		cerr << errmsg << endl;
	}
	return temp;
}

highNum operator /(highNum&& arg1, highNum& arg2)
{
	return arg1 / arg2;
}

highNum operator /(highNum& arg1, highNum&& arg2)
{
	return arg1 / arg2;
}

highNum operator /(highNum&& arg1, highNum&& arg2)
{
	return arg1 / arg2;
}

highNum operator /=(highNum& arg1, highNum arg2)
{
	return arg1 = arg1 / arg2;
}

highNum operator %(highNum& arg1, highNum& arg2)
{
	return mod(arg1, arg2, 0);
}

highNum operator %(highNum&& arg1, highNum& arg2)
{
	return arg1 % arg2;
}

highNum operator %(highNum& arg1, highNum&& arg2)
{
	return arg1 % arg2;
}

NC_API highNum operator %(highNum&& arg1, highNum&& arg2)
{
	return arg1 % arg2;
}

NC_API highNum operator %=(highNum& arg1, highNum arg2)
{
	return arg1 = arg1 % arg2;
}

//else
inline rsp::_Num divideFloor(const rsp::_Num& temp1, const rsp::_Num& temp2)//下取整
{
	if (!temp2)
		throw("Divisor cannot be zero!");
	if (temp1 % temp2 == 0)
		return temp1 / temp2;
	if (temp1 / temp2 > 0)
		return temp1 / temp2;
	else
		return temp1 / temp2 - 1;
}

inline rsp::_Num divideCeil(const rsp::_Num& temp1, const rsp::_Num& temp2)//上取整
{
	if (!temp2)
		throw("Divisor cannot be zero!");
	if (temp1 % temp2 == 0)
		return temp1 / temp2;
	if (temp1 / temp2 < 0)
		return temp1 / temp2;
	else
		return temp1 / temp2 + 1;
}
